home *** CD-ROM | disk | FTP | other *** search
- ******************************************
- ** OFFICIAL FakeMode DOCUMENTATION FILE **
- ******************************************
-
- written by Yaka/Xography in April/May 1994
- orthographic supervision by Sandman/Valhalla
-
-
-
- Hi, Dudes;
-
- I was asked about FakeMode and how I did it so often I thought I had to write
- a documentation about it. This documentation is written for all those who
- want to understand the principles behind FakeMode or even want to program
- the mode themselves. Feel free to use FakeMode in your own programs.
- There may be mistakes in this text, so you are self responsible for what may
- happen when you try to code FakeMode!
- There are a complete library with FakeMode routines and an example program
- for its use included with this doc. They were originally made for BC 3.1, but
- should be usable with other languages too. Just experiment with them!
-
-
- ---------
- CONTENTS:
- ---------
-
- Chapter 1. What is FakeMode?
- Chapter 2. The techniques behind FakeMode and how to program it
- Chapter 3. Information about the program included
- Chapter 4. Literature
-
-
-
- -----------------------------
- CHAPTER 1: What is FakeMode?
- -----------------------------
-
- FakeMode is a way to setup standard VGA cards so they are able to display
- more than 256 colors. I invented this mode in Xography's "Party93 Report"
- which was released in April 1994. So what is FakeMode good for?
-
- PRO FakeMode:
- -You have a screen resolution of 320x400
- -You have 3840 (fixed) colors on standard VGA's
-
- CONTRA FakeMode:
- - It is slow
- - The screen flickers a little
- - You need the timer interrupt
- - It works only on register compatible VGAs
- - setting pixels is difficult
- - the palette is fixed; so you can't choose the colors freely from 262144
-
-
- I think Fakemode is not useful for animations because:
- - you have to output 4 bytes to set 1 320x200 - Pixel ( -> slow)
- - screen memory access is rather complicated
- - slow movements will interfere with page flipping, this looks ugly
- (Hm, perhaps you'll find a way how to avoid this?)
-
-
-
- -----------------------------------------
- CHAPTER 2: The techniques behind FakeMode
- -----------------------------------------
-
- FakeMode is achieved by combination of several means:
-
- - Use Y-mode (320x400 at 256 colors and 2 pages)
- - Flip between the 2 pages at every vertical retrace
- - select the palette colors wisely
- - set pixel data in a special way.
-
-
- *** 2.1 Y-Mode
-
- Y-Mode (similar to X-mode) is a video mode for register compatible VGA cards,
- that pushes resolution up to 320x400 at still 256 colors and 2 pages! The
- disadvantage compared to standard mode 13h (320x200, 256col, 1 page) is that
- memory access is not so easy anymore (the pixels are split up in bitplanes).
- Here's the code I use to setup Y-Mode for FakedMode (in TASM 3.1) [1]:
-
- ********************************************
- _F_initgraph PROC
- push di ;//save DI because of BC (I call from BC)
- mov ax,0f00h ;//Get old videomode...
- int 10h
- mov oldvideomode,al ;//...and save it (define oldvideomode!)
-
- mov ax,0013h ;//initialize normal Mode 13h
- int 10h
-
- mov dx,3ceh ;//select Graphics Controller...
- mov al,5 ;//...Graphics Mode Register
- out dx,al
- inc dx
- in al,dx
- and al,11101111b ;//switch off ODD/EVEN mode
- out dx,al
- dec dx
-
- mov al,6 ;//...Miscellaneous Register
- out dx,al
- inc dx
- in al,dx
- and al,11111101b ;//switch off ODD/EVEN mode here, too
- out dx,al
-
- mov dx,3c4h ;//select Sequencer Controller...
- mov al,4 ;//...Memory Mode Register
- out dx,al
- inc dx
- in al,dx
- and al,11110111b ;//use linear adressing
- or al,4
- out dx,al
-
- mov ax,0a000h ;//access Video Memory
- mov es,ax
- xor di,di
- mov ax,di
- mov cx,8000h
- rep stosw ;//clear Screen
-
- mov dx,3d4h ;//select CRT Controller...
- mov al,9 ;//...Maximum Scan Line Register
- out dx,al
- inc dx
- in al,dx
- and al,01110000b ;//select 400 lines
- out dx,al
- dec dx
-
- mov al,14h ;//...Underline Location Register
- out dx,al
- inc dx
- in al,dx
- and al,10111111b ;//switch off Doubleword-Mode
- out dx,al
- dec dx
-
- mov al,17h ;//...Mode Control Register
- out dx,al
- inc dx
- in al,dx ;//select Word-Mode (normally: Bytemode)
- and al,10111111b ;//normally: or al,01000000b
- out dx,al
-
- call initpalette ;//call to palette setup routine (for FakeMode)
-
- call inittimer ;//call to timer setup routine (for FakeMode)
- pop di ;//restore value of di
- ret
- _F_initgraph ENDP
- ************************************
-
- That's it. I modified the original routine a bit as I keep WordMode;
- it's because it is easier to write FakeMode pixels in WordMode.
- You can return to textmode or other graphics modes by normal BIOS function
- call (int 10h, Fkt 0).
- The calls to 'initpalette' and 'inittimer' are necessary to install FakeMode
- and are not part of Y-Mode installation.
-
-
- *** 2.2 Page Flipping
-
- This is best done (I think) by synchronizing the timer interrupt with the
- screen. Just before the vertical retrace appears, the interrupt is called.
- The interrupt handler routine should now set the screen offset address to
- its new value and wait for the vertical retrace. Then it should reprogram
- the timer and return to the main program. When the vertical retrace occurs,
- the new offset address is loaded in the internal registers of the VGA card
- and invokes the next screen update. See [1], ([2]), [3].
-
- So we'll just have to:
- - hook the timer interrupt
- - write our own interrupt handler
- - synchronize the timer interrupt with the screen
- - still call system timer routine at 18.2 Hz from interrupt handler
- - program the timer chip to achieve MonoFlop mode.
-
- What could be simpler? :)
-
-
- *** 2.2.1 Hooking/Dehooking the timer interrupt,
- Synchronization with the screen
-
- Hooking an interrupt is quite easy; DOS interupt 21h has got functions to
- handle interrupt hooking (see below, routine inittimer).
- To synchronize the timer int with the screen, I first set the interrupt speed
- much faster than the screen (256 Hz) and use a handler that counts up a
- variable 'count'. Then I wait for a vertical retrace and let the timer run.
- When 'count' has changed at next vertical retrace, the timer still is too
- fast. I lower speed and try again, until 'count' doesn't change between start
- of timer and next vertical retrace. Then I know that with this speed, I'm just
- below the minimal speed. I increase it a little and now I know how long I
- have to wait aproximately between 2 timer int calls. Of course the value isn't
- exact, so I have to synchronize every interrupt call for new; that's done
- by the interrupt handler discussed below.
- The routine 'closetimer' should be called when you leave FakeMode; it stops
- the timer int and puts everything back to normal.
-
-
- ************************************
- synchroint PROC ;// This interrupt handler is used for
- push ax ;// screen synchronization.
- mov ax,counter
- inc ax ;// just count up 'counter'...
- mov counter,ax
- mov al,20h ;// send EOI to interrupt controller...
- out 20h,al
- pop ax
- iret ;// return from interrupt handler
- synchroint ENDP
-
- inittimer PROC ;// This routine is called when FakeMode is
- push di ;// installed. it initializes & synchronizes
- mov ax,1234h ;// the timer
- mov currentfloptime,ax ;// start with 256 Hz
-
- mov ax,3508h ;//save old Interrupt 08
- int 21h
- mov alterint08,bx
- mov alterint08+2,es
-
- xor ax,ax ;//redirect Int. 08 to Synchronisation Rout.
- mov es,ax
- mov di,08h*4 ;// this is the other method to access
- cli ;// interrupt vectors: via the interrupt table
- cld
- mov ax,offset synchroint
- stosw
- mov ax,cs
- stosw
- sti
-
- ;//------ synchronize timer with screen
-
- mov dx,3dah ;//Wait for End of Retrace
- s1endretjmp:
- in al,dx
- and al,00001000b
- jnz s1endretjmp
- s1retjmp: ;//Wait for Retrace
- in al,dx
- and al,00001000b
- jz s1retjmp
-
- synchroback: ;//now we can start measurement...
-
- mov al,36h ;//start Systemtimer in Rectangle Mode
- out 43h,al
- mov ax,currentfloptime
- out 40h,al
- mov al,ah
- out 40h,al
-
- mov ax,0 ;//reset counter. counter is increased
- mov counter, ax ;//by interrupt routine
-
- mov dx,3dah ;//Wait for End of Retrace
- s2endretjmp:
- in al,dx
- and al,00001000b
- jnz s2endretjmp
- s2retjmp: ;//Wait for Retrace
- in al,dx
- and al,00001000b
- jz s2retjmp
-
- mov ax,counter ;//did interrupt still occur?
- cmp ax,0
- je fertig ;//no -> ready
- mov ax,currentfloptime
- add ax,250 ;//yes -> lower speed and try again
- mov currentfloptime,ax
- jmp synchroback
-
- fertig:
- mov al,34h ;//set Systemtimer right (Monoflop)
- out 43h,al
- mov ax, currentfloptime
- sub ax,800 ;//...we need time for the handler
- mov currentfloptime,ax
- out 40h,al
- mov al,ah
- out 40h,al
-
- xor ax,ax ;//redirect Int. 08 to Screenswitch Routine
- mov es,ax
- mov di,08h*4
- cli
- cld
- mov ax,offset switchpageint ;//interrupt handler routine see below
- stosw
- mov ax,cs
- stosw
- sti
- pop di
- ret
- inittimer ENDP
-
- closetimer PROC ;// this routine de-installs the timer handler
- push ds
- push di
- push si
- cli
- mov al,36h ;//Systemtimer back to normal speed
- out 43h,al
- xor al,al
- out 40h,al
- out 40h,al
- push cs ;//restore Interrupt Vector back to normal
- pop ds
- mov si,offset alterint08
- xor ax,ax
- mov es,ax
- mov di,08h*4
- cld
- movsw
- movsw
- sti
- pop si
- pop di
- pop ds
- ret
- closetimer ENDP
- ************************************
-
-
- *** 2.2.2 The interrupt Handler routine
-
- This is the main timer interrupt routine which is called after every screen
- update and performs the page flipping.
- There are three necessary things when you write a hardware interrupt handler:
- 1) be sure to preserve ALL registers you use (push them and pop them later)!
- 2) don't forget to acknowledge the hardware interrupt controller
- (mov al,20h out 20h,al)!
- 3) return from Interrupt with IRET, not with RET!
-
- Read the comments; they should explain everything.
- Literature used for this: [2], [3]
-
- ************************************
- switchpageint PROC
- push ax ;//interrupt handlers must push all registers
- push bx ;//they use!
- push dx
-
- inc word ptr systimer ;//set system timer (this is my own timer;
- ;//i use it for timing in the main program)
- mov bx,currentpage
- add bx,32768
- mov currentpage,bx
- mov dx,3d4h
- mov al,0ch ;//set Start Adresse High (0Ch) to flip pages
- mov ah,bh
- out dx,ax
-
- mov dx,3dah ;//Wait for Retrace
- swretjmp: ;//(this is done to keep synchronization)
- in al,dx
- and al,00001000b
- jz swretjmp
-
- mov al,34h ;//start Monoflop for new
- out 43h,al ;//(let the timer run for new)
- mov ax,currentfloptime
- out 40h,al
- mov al,ah
- out 40h,al
-
- mov bx,currentsystimer ;//do Systemtimer call at 18.2 Hz
- add ax,bx
- mov currentsystimer,ax
- cmp ax,bx
- ja short nosysroutine ;//No --> continue
- pop dx
- pop bx
- pop ax
- jmp dword ptr alterint08 ;//call Systemtimer Routine
- nosysroutine:
- mov al,20h ;//OK to Interrupt Controller
- out 20h,al
-
- pop dx
- pop bx
- pop ax
- iret ;//return from interrupt
- switchpageint ENDP
- ************************************
-
- There may be timing problems when you use your own hardware interrupt handler.
- Especially the INT 13h calls are very time-sensitive, if a timer interrupt
- routine is called just when the processor is in INT13 handler, and the com-
- puting of the timer int takes too long, the computer may crash.
- In such cases it may help to check if the computer is just in the INT13 hand-
- ler when the timer interrupt is called (You have to hook int 13 and set a
- variable; then continue with int13 handler. After the handler has finished,
- reset the variable. So the timer int can check this variable to see if INT13
- handler is active or not.)
- Well, I never had problems with INT13 and FakeMode, so I didn't implement
- this. :)
-
-
- *** 2.3 Palette Setup
-
- The palette is static; that means I don't change it when I flip pages.
- To achieve the 3840 color mode, I split up the colors to green and red/blue.
- The palette contains 16*15 values red/blue and 16 values green (16*15+16=256).
- (16 colors red * 16 colors green * 15 colors blue = 3840 different colors)
- To get harmonic greys, I set blue to the same values as red and green, but
- just leave out the darkest blue value (you can't see that one, anyway).
- So when you set pixels later, you have to decrement the blue value if it
- isn't zero to get the right color. (The H_setsmallpixel routine of the
- example file included does that, for example.)
- The palette values are stored directly to DAC, but are also buffered in
- 'palette' to make later changes possible (fadein/out, setluminance).
-
-
- Here comes the palette setup routine:
-
- ************************************
- palette db 768 dup (?) ;//buffer for palette
-
- initpalette PROC
- push di
- push cs
- pop es
- mov di, offset palette
- cld
- mov dx,3c8h
- xor ax,ax
- xor bx,bx
- out dx,al
- inc dx ;//ah=red, bh=green, bl=blue
- mov cx,15
- initpal_outer: ;//setup red/blue part of palette (0..239)
- push cx
- mov cx,16
- initpal_inner:
- mov al,ah
- out dx,al
- stosb
- mov al,bh
- out dx,al
- stosb
- mov al,bl
- out dx,al
- stosb
-
- add ah,4
- loop initpal_inner
- mov ah,0
- add bl,4
- cmp bl,4
- jne goon
- add bl,4
- goon:
- pop cx
- loop initpal_outer
-
- mov cx,16
- xor ax,ax
- xor bx,bx
- initpal_second: ;//setup green part of palette (240..255)
- mov al,ah
- out dx,al
- stosb
- mov al,bh
- out dx,al
- stosb
- mov al,bl
- out dx,al
- stosb
- add bh,4
- loop initpal_second
- pop di
- ret
- initpalette ENDP
- ************************************
-
-
- *** How to set pixels in FakeMode
-
- The main purpose of the way I set pixels is to minimize the flicker.
- One pixel on the screen consists of 2 pixels, one on page 1 and one on
- page 2. On one of the pages the green value is displayed, on the other
- the red/blue value.
- Imagine I would set all pixels green values on page 1 and all red/blue
- values on page 2. I would get horrible flicker. To prevent this, I set
- the values like follows:
-
- if xpos+ypos=odd, then set red/blue on page 1 and green on page 2
- else set green on page 1 and red/blue on page 2.
-
- So I get a 1/1 raster, and each of the 2 pages contain both red/blue and
- green values. Look at the following routine to see how it is done exactly:
-
-
- ************************************
- _F_putsmallpixel PROC
- ;//values: x=0..319, y=0..399, red=0..15, green=0..15, blue=0..15
- ARG x:word, y:word, red:byte, green:byte, blue:byte
- push bp
- mov bp,sp
- push di
- mov bx,x
- mov cx,bx
- and cl,00000011b ;//calculate bitplane...
- mov dx,3c4h
- mov ax,0102h
- shl ah,cl
- out dx,ax ;//...and set it
- mov ax,0a000h ;//set destination segment
- mov es,ax
- mov ax,160 ;//set destination offset
- mov dx,y
- mul dx
- shr bx,1
- and bl,11111110b
- add bx,ax ;//bx contains basic offset
- mov di,bx
- mov al,blue ;//calculate red-blue value
- mov ah,16
- mul ah
- cmp ax,0
- je short smallpixgoon
- sub ax,16 ;// perform blue adjustment
- smallpixgoon:
- add al,red
- add cx,y
- and cl,00000001b ;// select if green value on page 1 or 2
- jz short stypetwo
- mov ah,al
- mov al,green
- add al,240
- mov es:[di],ax ;// set both pixels (on page 1 & 2)
- jmp short send
- stypetwo:
- mov ah,green
- add ah,240
- mov es:[di],ax ;// set both pixels (on page 1 & 2)
- send:
- pop di
- pop bp
- ret
- _F_putsmallpixel ENDP
- ************************************
-
-
- In FakeMode the video memory is built up like this:
-
- Bitplane 0| rb 0 | g 0 | g 4 | rb 4 | ...
- Bitplane 1| g 1 | rb 1 | rb 5 | g 5 | ...
- Bitplane 2| rb 2 | g 2 | g 6 | rb 6 | ...
- Bitplane 3| g 3 | rb 3 | rb 7 | g 7 | ...
- Offset | 0 | 1 | 2 | 3 | ...
-
- So one line on the screen uses 160 bytes of data in each Bitplane.
- The colors values for one pixel are stored besides each other (this is
- because I use wordmode).
-
-
- -------------------------------------------------
- CHAPTER 3: Information about the program included
- -------------------------------------------------
-
- With this doc comes an example program, written in BC 3.1 and TASM 3.1 .
- I also included the .PRJ file. (If the .PRJ file causes problems, create your
- own: Just be sure to include both FAKESHOW.CPP and FAKEMODE.ASM in your
- project and don't forget to set code generation to large.)
- There is also an example .TGA picture included (320x200, 24bit colors).
- This .TGA viewer will definitely only show UNPACKED 24-BIT .TGA pictures!
- (Perhaps you can extend this, but I considered it to be too much work for
- a little doc example). The viewer may display some of the .TGA pictures
- upside down; this is because the data is stored sometimes upside
- down. (I think there is a flag for this in the header of the .TGA).
- The file FAKEMODE.ASM is my complete FakeMode routine library and contains
- all useful basic routines concerning FakeMode.
-
-
- ---------------------
- CHAPTER 4: Literature
- ---------------------
-
- [1]: Michael Tischer: PC intern 3.0; Data Becker (a german book)
- Contains useful information about VGA programming
- (Although the Ferraro book might be better)
-
- [2]: DOS international, issue 3/89 p.170 ff; Everts&Hagedorn (german computer
- magazine). This is an article about how sample output
- with PC internal speaker is done. That's where I got
- timer / interrupt programming from
-
- [3]: A huge stack of copied sheets from several books I don't remember. :)
-
-
- ----------------------------------------------------------------------------
-
- So, I think this is enough. I hope you will be able to program FakeMode with
- this doc. If you haven't understood yet how FakeMode works, take a look at
- source in the example program.
- If you want to see what effects are possible with FakeMode, have a look at
- Xography's "Party'93 Report"... (You may find it in the internet on
- WASP.ENG.UFL.EDU, in /pub/msdos/demos/alpha/x, xgy_pr93.zip).
-
-
- (Oh, by the way: You can greet me in your FakeMode productions if you want :)
-
- Cheers,
- Yaka/Xography
-
-
-
-
- P.S.: If you have additional questions or suggestions, you can EMail to:
- uke4@rzstud1.rz.uni-karlsruhe.de
-
- (Please only send important messages, I don't want to have my mailbox
- flooded with "how-can-I-do-this"'s and "how-can-I-do-that"'s...
- And remember, I haven't got the time to answer all letters I receive,
- but I will try to read them all.)
-